(function () {		
//定义当前使用的开源组建的版本号
var OPEN_JS_T = {
    Jpegmeta : "201508011808" ,
    JpegEncoder : "201508011808" ,
    ImageCompress : "201508011808"
};

var uploadObj;
window.photo = {
		
maxUpload : 8,
// 上传信息 主要是 id 对应信息
uploadInfo: {},
// 上传队列，里面保存的是 id
uploadQueue: [],
// 预览队列，里面保存的是 id
previewQueue: [],
// 请求对象
xhr: {},
// 是否有任务正在上传
isBusy: false,
// fid
fid : 0,
tid : 0,
pId : 0,
qunId : 0,
	
    countUpload: function() {
        var num = 0;
        $.each(photo.uploadInfo, function(i, n) {
                if (n) {
                ++ num;
                }
        });

        return num;
    },

    getbuilder: function(s, filename, filedata, boundary) {
        var dashdash = '--',
        crlf = '\r\n',
        builder = '';

        for(var i in s.uploadformdata) {
            builder += dashdash;
            builder += boundary;
            builder += crlf;
            builder += 'Content-Disposition: form-data; name="' + i + '"';
            builder += crlf;
            builder += crlf;
            builder += s.uploadformdata[i];
            builder += crlf;
        }

        builder += dashdash;
        builder += boundary;
        builder += crlf;
        builder += 'Content-Disposition: form-data; name="' + s.uploadinputname + '"';
        builder += '; filename="' + filename + '"';
        builder += crlf;

        builder += 'Content-Type: application/octet-stream';
        builder += crlf;
        builder += crlf;

        builder += filedata;
        builder += crlf;

        builder += dashdash;
        builder += boundary;
        builder += dashdash;
        builder += crlf;
        return builder;
    },
	has_upload_list:function(ul,act){
		var textarea = ul.prev();
		var lis=$(ul).find("li");
		var imgList=new Array();
		$.each(lis,function(i,v){
			var imgs={};
			if($(v).attr("url")){
				imgs['file_url']=	$(v).attr("url");
				imgs['file_name']=	$(v).attr("name");
				imgList.push(imgs);
			}
		})
		if(imgList.length>0){
			textarea.val(JSON.stringify(imgList));
		}else{
			textarea.val("");	
		}
		if(act=="del"){
			textarea.trigger("BoxUploadDel");
		}
		if(act=="add"){
			textarea.trigger("BoxUploadAdd");
		}
		console.log(textarea.val());
	},
    // 图片预览
    uploadPreview: function(id) {

        var reader = new FileReader();
        var uploadBase64;
        var conf = {}, file = photo.uploadInfo[id].file;

        reader.onload = function(e) {
            var result = this.result;

            // 如果是jpg格式图片，读取图片拍摄方向,自动旋转
            if (file.type == 'image/jpeg'){
                var jpg = new JpegMeta.JpegFile(result, file.name);
                if (jpg.tiff && jpg.tiff.Orientation) {
					
        conf = {
            maxW: 800, //目标宽
            maxH: 800, //目标高
            quality: 0.8, //目标jpg图片输出质量
            orien: 1
        };
                    //设置旋转
				 conf = extend(conf, {
                                     orien: jpg.tiff.Orientation.value
                                     });
                }
            }

            // 压缩
            if (ImageCompresser.support()) {
                var img = new Image();
                img.onload = function() {
                    try {
                        uploadBase64 = ImageCompresser.getImageBase64(this, conf);
                    } catch (e) {
                        //TOOLS.dialog({content:'压缩图片失败',autoClose:true});
                        $('li#li' + id).remove();
                        return false;
                    }
                    if (uploadBase64.indexOf('data:image') < 0) {
                       // TOOLS.dialog({content:'上传照片格式不支持',autoClose:true});
                        $('li#li' + id).remove();
                        return false;
                    }

                    photo.uploadInfo[id].file = uploadBase64;//e.target.result;
                    photo.uploadInfo[id].filename = file.name;
                    $('li#li' + id).find('img').attr('src', uploadBase64);
                    photo.uploadQueue.push(id);
                }
                img.src = ImageCompresser.getFileObjectURL(file);
            } else {
                uploadBase64 = result; 
                if (uploadBase64.indexOf('data:image') < 0) {
                   // TOOLS.dialog({content:'上传照片格式不支持',autoClose:true});
                    $('li#li' + id).remove();
                    return false;
                }
                photo.uploadInfo[id].file = uploadBase64;//e.target.result;
                photo.uploadInfo[id].filename = file.name;
                $('li#li' + id).find('img').attr('src', uploadBase64);
                photo.uploadQueue.push(id);
            }

        }
        reader.readAsBinaryString(photo.uploadInfo[id].file);
    },

    _keys: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=', /*用于BASE64转码*/

    base64decode: function(input) {
        var output = '';
        var chr1, chr2, chr3 = '';
        var enc1, enc2, enc3, enc4 = '';
        var i = 0;
        if (input.length%4!=0){
            return '';
        }
        var base64test = /[^A-Za-z0-9\+\/\=]/g;
        if (base64test.exec(input)){
            return '';
        }
        do {
            enc1 = photo._keys.indexOf(input.charAt(i++));
            enc2 = photo._keys.indexOf(input.charAt(i++));
            enc3 = photo._keys.indexOf(input.charAt(i++));
            enc4 = photo._keys.indexOf(input.charAt(i++));
            chr1 = (enc1 << 2) | (enc2 >> 4);
            chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
            chr3 = ((enc3 & 3) << 6) | enc4;
            output = output + String.fromCharCode(chr1);
            if (enc3 != 64){
                output+=String.fromCharCode(chr2);
            }
            if (enc4 != 64){
                output+=String.fromCharCode(chr3);
            }
            chr1 = chr2 = chr3 = '';
            enc1 = enc2 = enc3 = enc4 = '';
        } while (i < input.length);
        return output;
    },

    // 创建上传请求
    createUpload: function(id,act) { 

        if (!photo.uploadInfo[id]) {
            return false;
        }
		
		var path=$('li#li' + id).parent().attr("path");
		var exts=$('li#li' + id).parent().attr("exts");
		if(typeof(exts)=="undefined")exts="";
		if(typeof(path)=="undefined")path="";
        // 图片posturl
		var uploadUrl =   '/BoxAddon/Upload/Index/upload/exts/'+exts+"/path/"+path;//alert(uploadUrl);
		//console.log(uploadUrl);
		 $('li#li' + id).prepend('<div class="maskLay"></div>');
		// 产生进度条
        var progressHtml = '<div class="progress" id="progress'+id+'"><div class="proBar" style="width:0%;"></div></div>';
		 //$('li#li' + id).prepend(progressHtml);
        $('li#li' + id).find('.maskLay').insertAfter(progressHtml);
        //var formData = new FormData();
       // formData.append('filedata', photo.uploadInfo[id].file);
       // formData.append('uid', uid); 
		/*formData.append('tid', topicid);
        formData.append('hash', uploadHash);
		formData.append('token', S_token);*/

        var progress = function(e) {
            if (e.target.response) {
                var result = $.parseJSON(e.target.response);
                if (result.errCode != 0) {
                    // $('#message').val(result.errCode);
                    //TOOLS.dialog({content:'网络不稳定，请稍后重新操作',autoClose:true});
                    removePic(id);
                }
            }

            var progress = $('#progress' + id).find('.proBar');
            if (e.total == e.loaded) {
                var percent = 100;
            } else {
                var percent = 100*(e.loaded / e.total);
            }
            // 控制进度条不要超出
            if (percent > 100) {
                percent = 100;
            }
            progress.css('width', percent + '%');

            if (percent == 100) {
                $('li#li' + id).find('.maskLay').remove();
                $('li#li' + id).find('.progress').remove();
            }
        }

        var removePic = function(id) {
            donePic(id);
            $('li#li' + id).remove();
			var ul=$('li#li' + id).parent();
			photo.has_upload_list(ul,"del");
        }

        var donePic = function(id) {
            photo.isBusy = false;
            photo.uploadInfo[id].isDone = true;
            photo.xhr[id] = null;

            /*var reportObj = {
                'a' : 'upload',
                'uid' : uid || ''
            };
            TOOLS.addReportCount(reportObj);*/
        }

        var complete = function(e) {
            //TOOLS.dialog({content:e.target.response,autoClose:true});
            // 上传结束
            donePic(id);
            /*
             返回值(纯文本) 如：DB|0|1051301|1|0
             DB为固定输出
             第一个0	代表报错信息，0为正常，非零为出错。
             第二个1051301	代表成功上传图片的附件aid
             第三个1	代表是否是图片
             第四个0	代表导致出错的上传文件容量的尺寸，比如1024000,则限制1024000字节以下的
             */ 
				//alert(e.target.response);
			//console.log(e);
            var response = JSON.parse(e.target.response);
			console.log(response);
			//if(response.error)
 		//	var attach = response.msg.split('|')
			//console.log(attach);
			//alert(attach.length);
            if(response.error== 0 ){ 
				var obj =$('li#li' + id);
				obj.attr("name",response.data.name);
				obj.attr("url",response.data.file_url);
                $('li#li' + id).find('.maskLay').remove();
                $('li#li' + id).find('.progress').remove();
				photo.has_upload_list($(obj).parent(),"add");
            }else{
				hiApp.alert(response.msg);
                removePic(id);
            }
		   
        }
		
		

        var failed = function() {
            photo.isBusy = false;
            photo.uploadInfo[id].isDone = true;
            //TOOLS.dialog({content:'网络断开，请稍后重新操作',autoClose:true});
            removePic(id)
        }

        var abort = function() {
            photo.isBusy = false;
            photo.uploadInfo[id].isDone = true;
            //TOOLS.dialog({content:'上传已取消',autoClose:true});
            removePic(id)
        }

        // 创建 ajax 请求
        photo.xhr[id] = new XMLHttpRequest();
        var boundary = '------multipartformboundary' + (new Date).getTime();
		var s = {
            uploadformdata:{ qunid:photo.qunId, topicid: photo.tid},
            uploadinputname:'filedata',
        };
		
        var picdata = photo.uploadInfo[id].file.replace(/data:.+;base64,/, '');
        if(typeof atob == 'function') {
            picdata = atob(picdata);
        } else {
            picdata = photo.base64decode(picdata);
        }
        var builder = photo.getbuilder(s, photo.uploadInfo[id].filename, picdata, boundary);
        photo.xhr[id].open("POST", uploadUrl, true);
        photo.xhr[id].setRequestHeader('content-type', 'multipart/form-data; boundary=' + boundary);
        if(!XMLHttpRequest.prototype.sendAsBinary){//如果XMLHttpRequest没有sendAsBinary
          XMLHttpRequest.prototype.sendAsBinary = function(datastr) {
            function byteValue(x) {
              return x.charCodeAt(0) & 0xff;
            }
            var ords = Array.prototype.map.call(datastr, byteValue);
            var ui8a = new Uint8Array(ords);
            this.send(ui8a.buffer);
          };
        }
        photo.xhr[id].sendAsBinary(builder);
        photo.xhr[id].onerror = function(e) {
            failed();
        };
        photo.xhr[id].onload = function(e) {
            complete(e);
        };
        photo.xhr[id].abort = function(e) {
            abort();
        };
        photo.xhr[id].onsendstream = function(e) {
            progress(e);
        };

    },
    // 上传相关
initUpload: function() {
		
		if (!photo.isBusy) { 
					$(document).on("touchstart", "#addPic", function () {
						$('#uploadFile').click();
					  });
                } else {
				     hiApp.alert('上传中，请稍后添加');
                     return false;
                }
				
      // 文件表单发生变化时
     $(document).on('change', '.uploadFile', function(e) {
	 	   uploadObj = $(this);	
		   var ul=$(this).parent().parent();	
           e = e || window.event;
           var fileList = e.target.files;
           if (!fileList.length) {
               return false;
           }
		   if($(ul).attr("maxUpload")){
			photo.maxUpload=$(ul).attr("maxUpload");
		   }
           for (var i = 0; i<fileList.length; i++) {
                if (photo.countUpload() >= photo.maxUpload) {
				   hiApp.alert('你最多只能上传'+photo.maxUpload+'个文件');
                break;
         	  }

           var file = fileList[i];

           if (!photo.checkPicSize(file)) {
			   hiApp.alert('文件体积过大');
                continue;
           }
          // if (!photo.checkPicType(file)) {
//			   hiApp.alert('上传文件格式不支持');
//                continue;
//           }

           var id = Date.now() + i;
           // 增加到上传对象中, 上传完成后，修改为 true
           photo.uploadInfo[id] = {
                file: file,
                filename: '',
                isDone: false,
           };

           var html = '<li id="li' + id + '"><div class="photoCut"><img src="/Public/images/defaultImg.jpg" class="attchImg" alt="photo"></div>' +
           '<div class="maskLay"></div>' +
           '<a href="javascript:" class="cBtn spr db "  _id="'+id+'">关闭</a></li>';
		   $('.photoList').find('ul').prepend(html);
           photo.previewQueue.push(id);
           }
           // 图片已经上传了 8 张，隐藏 + 号
           if (photo.countUpload() >= photo.maxUpload) {
                $(this).parent().hide();
           }

           // 把输入框清空
           $(this).val('');
        });
		
//删除		
$('.photoList').on("click", '.cBtn', function() {
            var id = $(this).attr('_id');
			var _this=$(this);
			var ul=$(this).parent().parent();
			var li=$(this).parent();
            // 取消这个请求
            if (photo.xhr[id]) {
                photo.xhr[id].abort();
            }
			
            // 图片删除
            $('li#li' + id).remove();
            photo.uploadInfo[id] = null;
			photo.has_upload_list(ul,"del");
			
            // 图片变少了，显示+号
            if (photo.countUpload() < photo.maxUpload) {
                $(ul).find(".uploadFile").parent().show();
            }
        });

        setInterval(function() {
            // 预览
            setTimeout(function() {
                       if (photo.previewQueue.length) {
                       var jobId = photo.previewQueue.shift();
                       photo.uploadPreview(jobId);
                       }
                       }, 1);
            // 上传
            setTimeout(function() {
                       if (!photo.isBusy && photo.uploadQueue.length) {
                       var jobId = photo.uploadQueue.shift();
                           photo.isBusy = true;
                           photo.createUpload(jobId,'topic');
                       }
                       }, 10);
            }, 300);
			
    },
 
    // 检查图片大小
    checkPicSize: function(file) {
        // 8M
        if (file.size > 10000000) {
            return false;
        }
        return true;
    },
    // 检查图片类型
    checkPicType: function(file) {

        if(file.type.indexOf('image/') == 0) {
            return true;
        }
        else {
            var index = file.name.lastIndexOf('.');
            var extName = file.name.substring(index+1).toLowerCase();
            if(extName == 'jpg' || extName == 'jpeg' || extName == 'png' || extName == 'gif' ) {
                return true;
            }
            return false;
        }
    }

    };

    return photo;
})();

/******jpegmeta.js*******/
var JpegMeta = {};
this.JpegMeta = JpegMeta;
JpegMeta.parseNum = function parseNum(endian, data, offset, size) {
    var i;
    var ret;
    var big_endian = (endian === ">");
    if (offset === undefined) offset = 0;
    if (size === undefined) size = data.length - offset;
    for (big_endian ? i = offset : i = offset + size - 1; big_endian ? i < offset + size : i >= offset; big_endian ? i++ : i--) {
        ret <<= 8;
        ret += data.charCodeAt(i);
    }
    return ret;
};
JpegMeta.parseSnum = function parseSnum(endian, data, offset, size) {
    var i;
    var ret;
    var neg;
    var big_endian = (endian === ">");
    if (offset === undefined) offset = 0;
    if (size === undefined) size = data.length - offset;
    for (big_endian ? i = offset : i = offset + size - 1; big_endian ? i < offset + size : i >= offset; big_endian ? i++ : i--) {
        if (neg === undefined) {
            neg = (data.charCodeAt(i) & 0x80) === 0x80;
        }
        ret <<= 8;
        ret += neg ? ~data.charCodeAt(i) & 0xff : data.charCodeAt(i);
    }
    if (neg) {
        ret += 1;
        ret *= -1;
    }
    return ret;
};
JpegMeta.Rational = function Rational(num, den) {
    this.num = num;
    this.den = den || 1;
    return this;
};
JpegMeta.Rational.prototype.toString = function toString() {
    if (this.num === 0) {
        return "" + this.num;
    }
    if (this.den === 1) {
        return "" + this.num;
    }
    if (this.num === 1) {
        return this.num + " / " + this.den;
    }
    return this.num / this.den;
};
JpegMeta.Rational.prototype.asFloat = function asFloat() {
    return this.num / this.den;
};
JpegMeta.MetaGroup = function MetaGroup(fieldName, description) {
    this.fieldName = fieldName;
    this.description = description;
    this.metaProps = {};
    return this;
};
JpegMeta.MetaGroup.prototype._addProperty = function _addProperty(fieldName, description, value) {
    var property = new JpegMeta.MetaProp(fieldName, description, value);
    this[property.fieldName] = property;
    this.metaProps[property.fieldName] = property;
};
JpegMeta.MetaGroup.prototype.toString = function toString() {
    return "[MetaGroup " + this.description + "]";
};
JpegMeta.MetaProp = function MetaProp(fieldName, description, value) {
    this.fieldName = fieldName;
    this.description = description;
    this.value = value;
    return this;
};
JpegMeta.MetaProp.prototype.toString = function toString() {
    return "" + this.value;
};
JpegMeta.JpegFile = function JpegFile(binary_data, filename) {
    var break_segment = this._SOS;
    this.metaGroups = {};
    this._binary_data = binary_data;
    this.filename = filename;
    var pos = 0;
    var pos_start_of_segment = 0;
    var delim;
    var mark;
    var _mark;
    var segsize;
    var headersize;
    var mark_code;
    var mark_fn;
    if (this._binary_data.slice(0, 2) !== this._SOI_MARKER) {
        throw new Error("Doesn't look like a JPEG file. First two bytes are " + this._binary_data.charCodeAt(0) + "," + this._binary_data.charCodeAt(1) + ".");
    }
    pos += 2;
    while (pos < this._binary_data.length) {
        delim = this._binary_data.charCodeAt(pos++);
        mark = this._binary_data.charCodeAt(pos++);
        console.log(mark.toString(16))
            pos_start_of_segment = pos;
        if (delim != this._DELIM) {
            break;
        }
        if (mark === break_segment) {
            break;
        }
        headersize = JpegMeta.parseNum(">", this._binary_data, pos, 2);
        console.log('headsize=' + headersize)
            pos += headersize;
        while (pos < this._binary_data.length) {
            delim = this._binary_data.charCodeAt(pos++);
            if (delim == this._DELIM) {
                _mark = this._binary_data.charCodeAt(pos++);
                if (_mark != 0x0) {
                    pos -= 2;
                    break;
                }
            }
        }
        segsize = pos - pos_start_of_segment;
        if (this._markers[mark]) {
            mark_code = this._markers[mark][0];
            mark_fn = this._markers[mark][1];
        } else {
            mark_code = "UNKN";
            mark_fn = undefined;
        }
        if (mark_fn) {
            this[mark_fn](mark, pos_start_of_segment + 2);
        }
    }
    if (this.general === undefined) {
        throw Error("Invalid JPEG file.");
    }
    return this;
};
this.JpegMeta.JpegFile.prototype.toString = function() {
    return "[JpegFile " + this.filename + " " + this.general.type + " " + this.general.pixelWidth + "x" + this.general.pixelHeight + " Depth: " + this.general.depth + "]";
};
this.JpegMeta.JpegFile.prototype._SOI_MARKER = '\xff\xd8';
this.JpegMeta.JpegFile.prototype._DELIM = 0xff;
this.JpegMeta.JpegFile.prototype._EOI = 0xd9;
this.JpegMeta.JpegFile.prototype._SOS = 0xda;
this.JpegMeta.JpegFile.prototype._sofHandler = function _sofHandler(mark, pos) {
    if (this.general !== undefined) {
        throw Error("Unexpected multiple-frame image");
    }
    this._addMetaGroup("general", "General");
    this.general._addProperty("depth", "Depth", JpegMeta.parseNum(">", this._binary_data, pos, 1));
    this.general._addProperty("pixelHeight", "Pixel Height", JpegMeta.parseNum(">", this._binary_data, pos + 1, 2));
    this.general._addProperty("pixelWidth", "Pixel Width", JpegMeta.parseNum(">", this._binary_data, pos + 3, 2));
    this.general._addProperty("type", "Type", this._markers[mark][2]);
};
this.JpegMeta.JpegFile.prototype._JFIF_IDENT = "JFIF\x00";
this.JpegMeta.JpegFile.prototype._JFXX_IDENT = "JFXX\x00";
this.JpegMeta.JpegFile.prototype._EXIF_IDENT = "Exif\x00";
this.JpegMeta.JpegFile.prototype._types = {
    1: ["BYTE", 1],
    2: ["ASCII", 1],
    3: ["SHORT", 2],
    4: ["LONG", 4],
    5: ["RATIONAL", 8],
    6: ["SBYTE", 1],
    7: ["UNDEFINED", 1],
    8: ["SSHORT", 2],
    9: ["SLONG", 4],
    10: ["SRATIONAL", 8],
    11: ["FLOAT", 4],
    12: ["DOUBLE", 8]
};
this.JpegMeta.JpegFile.prototype._tifftags = {
    256: ["Image width", "ImageWidth"],
    257: ["Image height", "ImageLength"],
    258: ["Number of bits per component", "BitsPerSample"],
    259: ["Compression scheme", "Compression",
    {
        1: "uncompressed",
        6: "JPEG compression"
    }],
    262: ["Pixel composition", "PhotmetricInerpretation",
    {
        2: "RGB",
        6: "YCbCr"
    }],
    274: ["Orientation of image", "Orientation",
    {
        1: "Normal",
        2: "Reverse?",
        3: "Upside-down",
        4: "Upside-down Reverse",
        5: "90 degree CW",
        6: "90 degree CW reverse",
        7: "90 degree CCW",
        8: "90 degree CCW reverse"
    }],
    277: ["Number of components", "SamplesPerPixel"],
    284: ["Image data arrangement", "PlanarConfiguration",
    {
        1: "chunky format",
        2: "planar format"
    }],
    530: ["Subsampling ratio of Y to C", "YCbCrSubSampling"],
    531: ["Y and C positioning", "YCbCrPositioning",
    {
        1: "centered",
        2: "co-sited"
    }],
    282: ["X Resolution", "XResolution"],
    283: ["Y Resolution", "YResolution"],
    296: ["Resolution Unit", "ResolutionUnit",
    {
        2: "inches",
        3: "centimeters"
    }],
    273: ["Image data location", "StripOffsets"],
    278: ["Number of rows per strip", "RowsPerStrip"],
    279: ["Bytes per compressed strip", "StripByteCounts"],
    513: ["Offset to JPEG SOI", "JPEGInterchangeFormat"],
    514: ["Bytes of JPEG Data", "JPEGInterchangeFormatLength"],
    301: ["Transfer function", "TransferFunction"],
    318: ["White point chromaticity", "WhitePoint"],
    319: ["Chromaticities of primaries", "PrimaryChromaticities"],
    529: ["Color space transformation matrix coefficients", "YCbCrCoefficients"],
    532: ["Pair of black and white reference values", "ReferenceBlackWhite"],
    306: ["Date and time", "DateTime"],
    270: ["Image title", "ImageDescription"],
    271: ["Make", "Make"],
    272: ["Model", "Model"],
    305: ["Software", "Software"],
    315: ["Person who created the image", "Artist"],
    316: ["Host Computer", "HostComputer"],
    33432: ["Copyright holder", "Copyright"],
    34665: ["Exif tag", "ExifIfdPointer"],
    34853: ["GPS tag", "GPSInfoIfdPointer"]
};
this.JpegMeta.JpegFile.prototype._exiftags = {
    36864: ["Exif Version", "ExifVersion"],
    40960: ["FlashPix Version", "FlashpixVersion"],
    40961: ["Color Space", "ColorSpace"],
    37121: ["Meaning of each component", "ComponentsConfiguration"],
    37122: ["Compressed Bits Per Pixel", "CompressedBitsPerPixel"],
    40962: ["Pixel X Dimension", "PixelXDimension"],
    40963: ["Pixel Y Dimension", "PixelYDimension"],
    37500: ["Manufacturer notes", "MakerNote"],
    37510: ["User comments", "UserComment"],
    40964: ["Related audio file", "RelatedSoundFile"],
    36867: ["Date Time Original", "DateTimeOriginal"],
    36868: ["Date Time Digitized", "DateTimeDigitized"],
    37520: ["DateTime subseconds", "SubSecTime"],
    37521: ["DateTimeOriginal subseconds", "SubSecTimeOriginal"],
    37522: ["DateTimeDigitized subseconds", "SubSecTimeDigitized"],
    33434: ["Exposure time", "ExposureTime"],
    33437: ["FNumber", "FNumber"],
    34850: ["Exposure program", "ExposureProgram"],
    34852: ["Spectral sensitivity", "SpectralSensitivity"],
    34855: ["ISO Speed Ratings", "ISOSpeedRatings"],
    34856: ["Optoelectric coefficient", "OECF"],
    37377: ["Shutter Speed", "ShutterSpeedValue"],
    37378: ["Aperture Value", "ApertureValue"],
    37379: ["Brightness", "BrightnessValue"],
    37380: ["Exposure Bias Value", "ExposureBiasValue"],
    37381: ["Max Aperture Value", "MaxApertureValue"],
    37382: ["Subject Distance", "SubjectDistance"],
    37383: ["Metering Mode", "MeteringMode"],
    37384: ["Light Source", "LightSource"],
    37385: ["Flash", "Flash"],
    37386: ["Focal Length", "FocalLength"],
    37396: ["Subject Area", "SubjectArea"],
    41483: ["Flash Energy", "FlashEnergy"],
    41484: ["Spatial Frequency Response", "SpatialFrequencyResponse"],
    41486: ["Focal Plane X Resolution", "FocalPlaneXResolution"],
    41487: ["Focal Plane Y Resolution", "FocalPlaneYResolution"],
    41488: ["Focal Plane Resolution Unit", "FocalPlaneResolutionUnit"],
    41492: ["Subject Location", "SubjectLocation"],
    41493: ["Exposure Index", "ExposureIndex"],
    41495: ["Sensing Method", "SensingMethod"],
    41728: ["File Source", "FileSource"],
    41729: ["Scene Type", "SceneType"],
    41730: ["CFA Pattern", "CFAPattern"],
    41985: ["Custom Rendered", "CustomRendered"],
    41986: ["Exposure Mode", "Exposure Mode"],
    41987: ["White Balance", "WhiteBalance"],
    41988: ["Digital Zoom Ratio", "DigitalZoomRatio"],
    41990: ["Scene Capture Type", "SceneCaptureType"],
    41991: ["Gain Control", "GainControl"],
    41992: ["Contrast", "Contrast"],
    41993: ["Saturation", "Saturation"],
    41994: ["Sharpness", "Sharpness"],
    41995: ["Device settings description", "DeviceSettingDescription"],
    41996: ["Subject distance range", "SubjectDistanceRange"],
    42016: ["Unique image ID", "ImageUniqueID"],
    40965: ["Interoperability tag", "InteroperabilityIFDPointer"]
};
this.JpegMeta.JpegFile.prototype._gpstags = {
    0: ["GPS tag version", "GPSVersionID"],
    1: ["North or South Latitude", "GPSLatitudeRef"],
    2: ["Latitude", "GPSLatitude"],
    3: ["East or West Longitude", "GPSLongitudeRef"],
    4: ["Longitude", "GPSLongitude"],
    5: ["Altitude reference", "GPSAltitudeRef"],
    6: ["Altitude", "GPSAltitude"],
    7: ["GPS time (atomic clock)", "GPSTimeStamp"],
    8: ["GPS satellites usedd for measurement", "GPSSatellites"],
    9: ["GPS receiver status", "GPSStatus"],
    10: ["GPS mesaurement mode", "GPSMeasureMode"],
    11: ["Measurement precision", "GPSDOP"],
    12: ["Speed unit", "GPSSpeedRef"],
    13: ["Speed of GPS receiver", "GPSSpeed"],
    14: ["Reference for direction of movement", "GPSTrackRef"],
    15: ["Direction of movement", "GPSTrack"],
    16: ["Reference for direction of image", "GPSImgDirectionRef"],
    17: ["Direction of image", "GPSImgDirection"],
    18: ["Geodetic survey data used", "GPSMapDatum"],
    19: ["Reference for latitude of destination", "GPSDestLatitudeRef"],
    20: ["Latitude of destination", "GPSDestLatitude"],
    21: ["Reference for longitude of destination", "GPSDestLongitudeRef"],
    22: ["Longitude of destination", "GPSDestLongitude"],
    23: ["Reference for bearing of destination", "GPSDestBearingRef"],
    24: ["Bearing of destination", "GPSDestBearing"],
    25: ["Reference for distance to destination", "GPSDestDistanceRef"],
    26: ["Distance to destination", "GPSDestDistance"],
    27: ["Name of GPS processing method", "GPSProcessingMethod"],
    28: ["Name of GPS area", "GPSAreaInformation"],
    29: ["GPS Date", "GPSDateStamp"],
    30: ["GPS differential correction", "GPSDifferential"]
};
this.JpegMeta.JpegFile.prototype._markers = {
    0xc0: ["SOF0", "_sofHandler", "Baseline DCT"],
    0xc1: ["SOF1", "_sofHandler", "Extended sequential DCT"],
    0xc2: ["SOF2", "_sofHandler", "Progressive DCT"],
    0xc3: ["SOF3", "_sofHandler", "Lossless (sequential)"],
    0xc5: ["SOF5", "_sofHandler", "Differential sequential DCT"],
    0xc6: ["SOF6", "_sofHandler", "Differential progressive DCT"],
    0xc7: ["SOF7", "_sofHandler", "Differential lossless (sequential)"],
    0xc8: ["JPG", null, "Reserved for JPEG extensions"],
    0xc9: ["SOF9", "_sofHandler", "Extended sequential DCT"],
    0xca: ["SOF10", "_sofHandler", "Progressive DCT"],
    0xcb: ["SOF11", "_sofHandler", "Lossless (sequential)"],
    0xcd: ["SOF13", "_sofHandler", "Differential sequential DCT"],
    0xce: ["SOF14", "_sofHandler", "Differential progressive DCT"],
    0xcf: ["SOF15", "_sofHandler", "Differential lossless (sequential)"],
    0xc4: ["DHT", null, "Define Huffman table(s)"],
    0xcc: ["DAC", null, "Define arithmetic coding conditioning(s)"],
    0xd0: ["RST0", null, "Restart with modulo 8 count “0”"],
    0xd1: ["RST1", null, "Restart with modulo 8 count “1”"],
    0xd2: ["RST2", null, "Restart with modulo 8 count “2”"],
    0xd3: ["RST3", null, "Restart with modulo 8 count “3”"],
    0xd4: ["RST4", null, "Restart with modulo 8 count “4”"],
    0xd5: ["RST5", null, "Restart with modulo 8 count “5”"],
    0xd6: ["RST6", null, "Restart with modulo 8 count “6”"],
    0xd7: ["RST7", null, "Restart with modulo 8 count “7”"],
    0xd8: ["SOI", null, "Start of image"],
    0xd9: ["EOI", null, "End of image"],
    0xda: ["SOS", null, "Start of scan"],
    0xdb: ["DQT", null, "Define quantization table(s)"],
    0xdc: ["DNL", null, "Define number of lines"],
    0xdd: ["DRI", null, "Define restart interval"],
    0xde: ["DHP", null, "Define hierarchical progression"],
    0xdf: ["EXP", null, "Expand reference component(s)"],
    0xe0: ["APP0", "_app0Handler", "Reserved for application segments"],
    0xe1: ["APP1", "_app1Handler"],
    0xe2: ["APP2", null],
    0xe3: ["APP3", null],
    0xe4: ["APP4", null],
    0xe5: ["APP5", null],
    0xe6: ["APP6", null],
    0xe7: ["APP7", null],
    0xe8: ["APP8", null],
    0xe9: ["APP9", null],
    0xea: ["APP10", null],
    0xeb: ["APP11", null],
    0xec: ["APP12", null],
    0xed: ["APP13", null],
    0xee: ["APP14", null],
    0xef: ["APP15", null],
    0xf0: ["JPG0", null],
    0xf1: ["JPG1", null],
    0xf2: ["JPG2", null],
    0xf3: ["JPG3", null],
    0xf4: ["JPG4", null],
    0xf5: ["JPG5", null],
    0xf6: ["JPG6", null],
    0xf7: ["JPG7", null],
    0xf8: ["JPG8", null],
    0xf9: ["JPG9", null],
    0xfa: ["JPG10", null],
    0xfb: ["JPG11", null],
    0xfc: ["JPG12", null],
    0xfd: ["JPG13", null],
    0xfe: ["COM", null],
    0x01: ["JPG13", null]
};
this.JpegMeta.JpegFile.prototype._addMetaGroup = function _addMetaGroup(name, description) {
    var group = new JpegMeta.MetaGroup(name, description);
    this[group.fieldName] = group;
    this.metaGroups[group.fieldName] = group;
    return group;
};
this.JpegMeta.JpegFile.prototype._parseIfd = function _parseIfd(endian, _binary_data, base, ifd_offset, tags, name, description) {
    var num_fields = JpegMeta.parseNum(endian, _binary_data, base + ifd_offset, 2);
    var i, j;
    var tag_base;
    var tag_field;
    var type, type_field, type_size;
    var num_values;
    var value_offset;
    var value;
    var _val;
    var num;
    var den;
    var group;
    group = this._addMetaGroup(name, description);
    for (var i = 0; i < num_fields; i++) {
        tag_base = base + ifd_offset + 2 + (i * 12);
        tag_field = JpegMeta.parseNum(endian, _binary_data, tag_base, 2);
        console.log('tag-field=' + tag_field)
            type_field = JpegMeta.parseNum(endian, _binary_data, tag_base + 2, 2);
        num_values = JpegMeta.parseNum(endian, _binary_data, tag_base + 4, 4);
        value_offset = JpegMeta.parseNum(endian, _binary_data, tag_base + 8, 4);
        if (this._types[type_field] === undefined) {
            continue;
        }
        type = this._types[type_field][0];
        type_size = this._types[type_field][1];
        if (type_size * num_values <= 4) {
            value_offset = tag_base + 8;
        } else {
            value_offset = base + value_offset;
        }
        if (type == "UNDEFINED") {
            f = _binary_data.slice(value_offset, value_offset + num_values);
        } else if (type == "ASCII") {
            value = _binary_data.slice(value_offset, value_offset + num_values);
            value = value.split('\x00')[0];
        } else {
            value = new Array();
            for (j = 0; j < num_values; j++, value_offset += type_size) {
                if (type == "BYTE" || type == "SHORT" || type == "LONG") {
                    value.push(JpegMeta.parseNum(endian, _binary_data, value_offset, type_size));
                }
                if (type == "SBYTE" || type == "SSHORT" || type == "SLONG") {
                    value.push(JpegMeta.parseSnum(endian, _binary_data, value_offset, type_size));
                }
                if (type == "RATIONAL") {
                    num = JpegMeta.parseNum(endian, _binary_data, value_offset, 4);
                    den = JpegMeta.parseNum(endian, _binary_data, value_offset + 4, 4);
                    value.push(new JpegMeta.Rational(num, den));
                }
                if (type == "SRATIONAL") {
                    num = JpegMeta.parseSnum(endian, _binary_data, value_offset, 4);
                    den = JpegMeta.parseSnum(endian, _binary_data, value_offset + 4, 4);
                    value.push(new JpegMeta.Rational(num, den));
                }
                value.push();
            }
            if (num_values === 1) {
                value = value[0];
            }
        }
        if (tags[tag_field] !== undefined) {
            group._addProperty(tags[tag_field][1], tags[tag_field][0], value);
        }
    }
};
this.JpegMeta.JpegFile.prototype._jfifHandler = function _jfifHandler(mark, pos) {
    if (this.jfif !== undefined) {
        throw Error("Multiple JFIF segments found");
    }
    this._addMetaGroup("jfif", "JFIF");
    this.jfif._addProperty("version_major", "Version Major", this._binary_data.charCodeAt(pos + 5));
    this.jfif._addProperty("version_minor", "Version Minor", this._binary_data.charCodeAt(pos + 6));
    this.jfif._addProperty("version", "JFIF Version", this.jfif.version_major.value + "." + this.jfif.version_minor.value);
    this.jfif._addProperty("units", "Density Unit", this._binary_data.charCodeAt(pos + 7));
    this.jfif._addProperty("Xdensity", "X density", JpegMeta.parseNum(">", this._binary_data, pos + 8, 2));
    this.jfif._addProperty("Ydensity", "Y Density", JpegMeta.parseNum(">", this._binary_data, pos + 10, 2));
    this.jfif._addProperty("Xthumbnail", "X Thumbnail", JpegMeta.parseNum(">", this._binary_data, pos + 12, 1));
    this.jfif._addProperty("Ythumbnail", "Y Thumbnail", JpegMeta.parseNum(">", this._binary_data, pos + 13, 1));
};
this.JpegMeta.JpegFile.prototype._app0Handler = function app0Handler(mark, pos) {
    var ident = this._binary_data.slice(pos, pos + 5);
    if (ident == this._JFIF_IDENT) {
        this._jfifHandler(mark, pos);
    } else if (ident == this._JFXX_IDENT) {} else {}
};
this.JpegMeta.JpegFile.prototype._app1Handler = function _app1Handler(mark, pos) {
    var ident = this._binary_data.slice(pos, pos + 5);
    if (ident == this._EXIF_IDENT) {
        this._exifHandler(mark, pos + 6);
    } else {}
};
JpegMeta.JpegFile.prototype._exifHandler = function _exifHandler(mark, pos) {
    if (this.exif !== undefined) {
        throw new Error("Multiple JFIF segments found");
    }
    var endian;
    var magic_field;
    var ifd_offset;
    var primary_ifd, exif_ifd, gps_ifd;
    var endian_field = this._binary_data.slice(pos, pos + 2);
    if (endian_field === "II") {
        endian = "<";
    } else if (endian_field === "MM") {
        endian = ">";
    } else {
        throw new Error("Malformed TIFF meta-data. Unknown endianess: " + endian_field);
    }
    magic_field = JpegMeta.parseNum(endian, this._binary_data, pos + 2, 2);
    if (magic_field !== 42) {
        throw new Error("Malformed TIFF meta-data. Bad magic: " + magic_field);
    }
    ifd_offset = JpegMeta.parseNum(endian, this._binary_data, pos + 4, 4);
    this._parseIfd(endian, this._binary_data, pos, ifd_offset, this._tifftags, "tiff", "TIFF");
        if (this.tiff.ExifIfdPointer) {
            console.log('has pointer1')
                this._parseIfd(endian, this._binary_data, pos, this.tiff.ExifIfdPointer.value, this._exiftags, "exif", "Exif");
        }
    if (this.tiff.GPSInfoIfdPointer) {
        this._parseIfd(endian, this._binary_data, pos, this.tiff.GPSInfoIfdPointer.value, this._gpstags, "gps", "GPS");
        if (this.gps.GPSLatitude) {
            var latitude;
            latitude = this.gps.GPSLatitude.value[0].asFloat() + (1 / 60) * this.gps.GPSLatitude.value[1].asFloat() + (1 / 3600) * this.gps.GPSLatitude.value[2].asFloat();
            if (this.gps.GPSLatitudeRef.value === "S") {
                latitude = -latitude;
            }
            this.gps._addProperty("latitude", "Dec. Latitude", latitude);
        }
        if (this.gps.GPSLongitude) {
            var longitude;
            longitude = this.gps.GPSLongitude.value[0].asFloat() + (1 / 60) * this.gps.GPSLongitude.value[1].asFloat() + (1 / 3600) * this.gps.GPSLongitude.value[2].asFloat();
            if (this.gps.GPSLongitudeRef.value === "W") {
                longitude = -longitude;
            }
            this.gps._addProperty("longitude", "Dec. Longitude", longitude);
        }
    }
};

/*****jpeg.encoder.basic.js****/
function JPEGEncoder(quality){var self=this;var fround=Math.round;var ffloor=Math.floor;var YTable=new Array(64);var UVTable=new Array(64);var fdtbl_Y=new Array(64);var fdtbl_UV=new Array(64);var YDC_HT;var UVDC_HT;var YAC_HT;var UVAC_HT;var bitcode=new Array(65535);var category=new Array(65535);var outputfDCTQuant=new Array(64);var DU=new Array(64);var byteout=[];var bytenew=0;var bytepos=7;var YDU=new Array(64);var UDU=new Array(64);var VDU=new Array(64);var clt=new Array(256);var RGB_YUV_TABLE=new Array(2048);var currentQuality;var ZigZag=[0,1,5,6,14,15,27,28,2,4,7,13,16,26,29,42,3,8,12,17,25,30,41,43,9,11,18,24,31,40,44,53,10,19,23,32,39,45,52,54,20,22,33,38,46,51,55,60,21,34,37,47,50,56,59,61,35,36,48,49,57,58,62,63];var std_dc_luminance_nrcodes=[0,0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0];var std_dc_luminance_values=[0,1,2,3,4,5,6,7,8,9,10,11];var std_ac_luminance_nrcodes=[0,0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d];var std_ac_luminance_values=[0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12,0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07,0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08,0x23,0x42,0xb1,0xc1,0x15,0x52,0xd1,0xf0,0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16,0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28,0x29,0x2a,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa];var std_dc_chrominance_nrcodes=[0,0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0];var std_dc_chrominance_values=[0,1,2,3,4,5,6,7,8,9,10,11];var std_ac_chrominance_nrcodes=[0,0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,0x77];var std_ac_chrominance_values=[0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71,0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91,0xa1,0xb1,0xc1,0x09,0x23,0x33,0x52,0xf0,0x15,0x62,0x72,0xd1,0x0a,0x16,0x24,0x34,0xe1,0x25,0xf1,0x17,0x18,0x19,0x1a,0x26,0x27,0x28,0x29,0x2a,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa];function initQuantTables(sf){var YQT=[16,11,10,16,24,40,51,61,12,12,14,19,26,58,60,55,14,13,16,24,40,57,69,56,14,17,22,29,51,87,80,62,18,22,37,56,68,109,103,77,24,35,55,64,81,104,113,92,49,64,78,87,103,121,120,101,72,92,95,98,112,100,103,99];for(var i=0;i<64;i++){var t=ffloor((YQT[i]*sf+50)/100);if(t<1){t=1;}else if(t>255){t=255;}
YTable[ZigZag[i]]=t;}
var UVQT=[17,18,24,47,99,99,99,99,18,21,26,66,99,99,99,99,24,26,56,99,99,99,99,99,47,66,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99];for(var j=0;j<64;j++){var u=ffloor((UVQT[j]*sf+50)/100);if(u<1){u=1;}else if(u>255){u=255;}
UVTable[ZigZag[j]]=u;}
var aasf=[1.0,1.387039845,1.306562965,1.175875602,1.0,0.785694958,0.541196100,0.275899379];var k=0;for(var row=0;row<8;row++)
{for(var col=0;col<8;col++)
{fdtbl_Y[k]=(1.0/(YTable[ZigZag[k]]*aasf[row]*aasf[col]*8.0));fdtbl_UV[k]=(1.0/(UVTable[ZigZag[k]]*aasf[row]*aasf[col]*8.0));k++;}}}
function computeHuffmanTbl(nrcodes,std_table){var codevalue=0;var pos_in_table=0;var HT=new Array();for(var k=1;k<=16;k++){for(var j=1;j<=nrcodes[k];j++){HT[std_table[pos_in_table]]=[];HT[std_table[pos_in_table]][0]=codevalue;HT[std_table[pos_in_table]][1]=k;pos_in_table++;codevalue++;}
codevalue*=2;}
return HT;}
function initHuffmanTbl()
{YDC_HT=computeHuffmanTbl(std_dc_luminance_nrcodes,std_dc_luminance_values);UVDC_HT=computeHuffmanTbl(std_dc_chrominance_nrcodes,std_dc_chrominance_values);YAC_HT=computeHuffmanTbl(std_ac_luminance_nrcodes,std_ac_luminance_values);UVAC_HT=computeHuffmanTbl(std_ac_chrominance_nrcodes,std_ac_chrominance_values);}
function initCategoryNumber()
{var nrlower=1;var nrupper=2;for(var cat=1;cat<=15;cat++){for(var nr=nrlower;nr<nrupper;nr++){category[32767+nr]=cat;bitcode[32767+nr]=[];bitcode[32767+nr][1]=cat;bitcode[32767+nr][0]=nr;}
for(var nrneg=-(nrupper-1);nrneg<=-nrlower;nrneg++){category[32767+nrneg]=cat;bitcode[32767+nrneg]=[];bitcode[32767+nrneg][1]=cat;bitcode[32767+nrneg][0]=nrupper-1+nrneg;}
nrlower<<=1;nrupper<<=1;}}
function initRGBYUVTable(){for(var i=0;i<256;i++){RGB_YUV_TABLE[i]=19595*i;RGB_YUV_TABLE[(i+256)>>0]=38470*i;RGB_YUV_TABLE[(i+512)>>0]=7471*i+0x8000;RGB_YUV_TABLE[(i+768)>>0]=-11059*i;RGB_YUV_TABLE[(i+1024)>>0]=-21709*i;RGB_YUV_TABLE[(i+1280)>>0]=32768*i+0x807FFF;RGB_YUV_TABLE[(i+1536)>>0]=-27439*i;RGB_YUV_TABLE[(i+1792)>>0]=-5329*i;}}
function writeBits(bs)
{var value=bs[0];var posval=bs[1]-1;while(posval>=0){if(value&(1<<posval)){bytenew|=(1<<bytepos);}
posval--;bytepos--;if(bytepos<0){if(bytenew==0xFF){writeByte(0xFF);writeByte(0);}
else{writeByte(bytenew);}
bytepos=7;bytenew=0;}}}
function writeByte(value)
{byteout.push(clt[value]);}
function writeWord(value)
{writeByte((value>>8)&0xFF);writeByte((value)&0xFF);}
function fDCTQuant(data,fdtbl)
{var d0,d1,d2,d3,d4,d5,d6,d7;var dataOff=0;var i;const I8=8;const I64=64;for(i=0;i<I8;++i)
{d0=data[dataOff];d1=data[dataOff+1];d2=data[dataOff+2];d3=data[dataOff+3];d4=data[dataOff+4];d5=data[dataOff+5];d6=data[dataOff+6];d7=data[dataOff+7];var tmp0=d0+d7;var tmp7=d0-d7;var tmp1=d1+d6;var tmp6=d1-d6;var tmp2=d2+d5;var tmp5=d2-d5;var tmp3=d3+d4;var tmp4=d3-d4;var tmp10=tmp0+tmp3;var tmp13=tmp0-tmp3;var tmp11=tmp1+tmp2;var tmp12=tmp1-tmp2;data[dataOff]=tmp10+tmp11;data[dataOff+4]=tmp10-tmp11;var z1=(tmp12+tmp13)*0.707106781;data[dataOff+2]=tmp13+z1;data[dataOff+6]=tmp13-z1;tmp10=tmp4+tmp5;tmp11=tmp5+tmp6;tmp12=tmp6+tmp7;var z5=(tmp10-tmp12)*0.382683433;var z2=0.541196100*tmp10+z5;var z4=1.306562965*tmp12+z5;var z3=tmp11*0.707106781;var z11=tmp7+z3;var z13=tmp7-z3;data[dataOff+5]=z13+z2;data[dataOff+3]=z13-z2;data[dataOff+1]=z11+z4;data[dataOff+7]=z11-z4;dataOff+=8;}
dataOff=0;for(i=0;i<I8;++i)
{d0=data[dataOff];d1=data[dataOff+8];d2=data[dataOff+16];d3=data[dataOff+24];d4=data[dataOff+32];d5=data[dataOff+40];d6=data[dataOff+48];d7=data[dataOff+56];var tmp0p2=d0+d7;var tmp7p2=d0-d7;var tmp1p2=d1+d6;var tmp6p2=d1-d6;var tmp2p2=d2+d5;var tmp5p2=d2-d5;var tmp3p2=d3+d4;var tmp4p2=d3-d4;var tmp10p2=tmp0p2+tmp3p2;var tmp13p2=tmp0p2-tmp3p2;var tmp11p2=tmp1p2+tmp2p2;var tmp12p2=tmp1p2-tmp2p2;data[dataOff]=tmp10p2+tmp11p2;data[dataOff+32]=tmp10p2-tmp11p2;var z1p2=(tmp12p2+tmp13p2)*0.707106781;data[dataOff+16]=tmp13p2+z1p2;data[dataOff+48]=tmp13p2-z1p2;tmp10p2=tmp4p2+tmp5p2;tmp11p2=tmp5p2+tmp6p2;tmp12p2=tmp6p2+tmp7p2;var z5p2=(tmp10p2-tmp12p2)*0.382683433;var z2p2=0.541196100*tmp10p2+z5p2;var z4p2=1.306562965*tmp12p2+z5p2;var z3p2=tmp11p2*0.707106781;var z11p2=tmp7p2+z3p2;var z13p2=tmp7p2-z3p2;data[dataOff+40]=z13p2+z2p2;data[dataOff+24]=z13p2-z2p2;data[dataOff+8]=z11p2+z4p2;data[dataOff+56]=z11p2-z4p2;dataOff++;}
var fDCTQuant;for(i=0;i<I64;++i)
{fDCTQuant=data[i]*fdtbl[i];outputfDCTQuant[i]=(fDCTQuant>0.0)?((fDCTQuant+0.5)|0):((fDCTQuant-0.5)|0);}
return outputfDCTQuant;}
function writeAPP0()
{writeWord(0xFFE0);writeWord(16);writeByte(0x4A);writeByte(0x46);writeByte(0x49);writeByte(0x46);writeByte(0);writeByte(1);writeByte(1);writeByte(0);writeWord(1);writeWord(1);writeByte(0);writeByte(0);}

function writeSOF0(width,height)
{writeWord(0xFFC0);writeWord(17);writeByte(8);writeWord(height);writeWord(width);writeByte(3);writeByte(1);writeByte(0x11);writeByte(0);writeByte(2);writeByte(0x11);writeByte(1);writeByte(3);writeByte(0x11);writeByte(1);}
function writeDQT()
{writeWord(0xFFDB);writeWord(132);writeByte(0);for(var i=0;i<64;i++){writeByte(YTable[i]);}
writeByte(1);for(var j=0;j<64;j++){writeByte(UVTable[j]);}}
function writeDHT()
{writeWord(0xFFC4);writeWord(0x01A2);writeByte(0);for(var i=0;i<16;i++){writeByte(std_dc_luminance_nrcodes[i+1]);}
for(var j=0;j<=11;j++){writeByte(std_dc_luminance_values[j]);}
writeByte(0x10);for(var k=0;k<16;k++){writeByte(std_ac_luminance_nrcodes[k+1]);}
for(var l=0;l<=161;l++){writeByte(std_ac_luminance_values[l]);}
writeByte(1);for(var m=0;m<16;m++){writeByte(std_dc_chrominance_nrcodes[m+1]);}
for(var n=0;n<=11;n++){writeByte(std_dc_chrominance_values[n]);}
writeByte(0x11);for(var o=0;o<16;o++){writeByte(std_ac_chrominance_nrcodes[o+1]);}
for(var p=0;p<=161;p++){writeByte(std_ac_chrominance_values[p]);}}
function writeSOS()
{writeWord(0xFFDA);writeWord(12);writeByte(3);writeByte(1);writeByte(0);writeByte(2);writeByte(0x11);writeByte(3);writeByte(0x11);writeByte(0);writeByte(0x3f);writeByte(0);}
function processDU(CDU,fdtbl,DC,HTDC,HTAC){var EOB=HTAC[0x00];var M16zeroes=HTAC[0xF0];var pos;const I16=16;const I63=63;const I64=64;var DU_DCT=fDCTQuant(CDU,fdtbl);for(var j=0;j<I64;++j){DU[ZigZag[j]]=DU_DCT[j];}
var Diff=DU[0]-DC;DC=DU[0];if(Diff==0){writeBits(HTDC[0]);}else{pos=32767+Diff;writeBits(HTDC[category[pos]]);writeBits(bitcode[pos]);}
var end0pos=63;for(;(end0pos>0)&&(DU[end0pos]==0);end0pos--){};if(end0pos==0){writeBits(EOB);return DC;}
var i=1;var lng;while(i<=end0pos){var startpos=i;for(;(DU[i]==0)&&(i<=end0pos);++i){}
var nrzeroes=i-startpos;if(nrzeroes>=I16){lng=nrzeroes>>4;for(var nrmarker=1;nrmarker<=lng;++nrmarker)
writeBits(M16zeroes);nrzeroes=nrzeroes&0xF;}
pos=32767+DU[i];writeBits(HTAC[(nrzeroes<<4)+category[pos]]);writeBits(bitcode[pos]);i++;}
if(end0pos!=I63){writeBits(EOB);}
return DC;}
function initCharLookupTable(){var sfcc=String.fromCharCode;for(var i=0;i<256;i++){clt[i]=sfcc(i);}}
this.encode=function(image,quality)
{var time_start=new Date().getTime();if(quality)setQuality(quality);byteout=new Array();bytenew=0;bytepos=7;writeWord(0xFFD8);writeAPP0();writeDQT();writeSOF0(image.width,image.height);writeDHT();writeSOS();var DCY=0;var DCU=0;var DCV=0;bytenew=0;bytepos=7;this.encode.displayName="_encode_";var imageData=image.data;var width=image.width;var height=image.height;var quadWidth=width*4;var tripleWidth=width*3;var x,y=0;var r,g,b;var start,p,col,row,pos;while(y<height){x=0;while(x<quadWidth){start=quadWidth*y+x;p=start;col=-1;row=0;for(pos=0;pos<64;pos++){row=pos>>3;col=(pos&7)*4;p=start+(row*quadWidth)+col;if(y+row>=height){p-=(quadWidth*(y+1+row-height));}
if(x+col>=quadWidth){p-=((x+col)-quadWidth+4)}
r=imageData[p++];g=imageData[p++];b=imageData[p++];YDU[pos]=((RGB_YUV_TABLE[r]+RGB_YUV_TABLE[(g+256)>>0]+RGB_YUV_TABLE[(b+512)>>0])>>16)-128;UDU[pos]=((RGB_YUV_TABLE[(r+768)>>0]+RGB_YUV_TABLE[(g+1024)>>0]+RGB_YUV_TABLE[(b+1280)>>0])>>16)-128;VDU[pos]=((RGB_YUV_TABLE[(r+1280)>>0]+RGB_YUV_TABLE[(g+1536)>>0]+RGB_YUV_TABLE[(b+1792)>>0])>>16)-128;}
DCY=processDU(YDU,fdtbl_Y,DCY,YDC_HT,YAC_HT);DCU=processDU(UDU,fdtbl_UV,DCU,UVDC_HT,UVAC_HT);DCV=processDU(VDU,fdtbl_UV,DCV,UVDC_HT,UVAC_HT);x+=32;}
y+=8;}
if(bytepos>=0){var fillbits=[];fillbits[1]=bytepos+1;fillbits[0]=(1<<(bytepos+1))-1;writeBits(fillbits);}
writeWord(0xFFD9);var jpegDataUri='data:image/jpeg;base64,'+btoa(byteout.join(''));byteout=[];var duration=new Date().getTime()-time_start;console.log('Encoding time: '+duration+'ms');return jpegDataUri}
function setQuality(quality){if(quality<=0){quality=1;}
if(quality>100){quality=100;}
if(currentQuality==quality)return
var sf=0;if(quality<50){sf=Math.floor(5000/quality);}else{sf=Math.floor(200-quality*2);}
initQuantTables(sf);currentQuality=quality;console.log('Quality set to: '+quality+'%');}
function init(){var time_start=new Date().getTime();if(!quality)quality=50;initCharLookupTable()
initHuffmanTbl();initCategoryNumber();initRGBYUVTable();setQuality(quality);var duration=new Date().getTime()-time_start;console.log('Initialization '+duration+'ms');}
init();};function getImageDataFromImage(idOrElement){var theImg=(typeof(idOrElement)=='string')?document.getElementById(idOrElement):idOrElement;var cvs=document.createElement('canvas');cvs.width=theImg.width;cvs.height=theImg.height;var ctx=cvs.getContext("2d");ctx.drawImage(theImg,0,0);return(ctx.getImageData(0,0,cvs.width,cvs.height));}
/*****image_compress.js**/
/**
 * 图片压缩静态类 from qzone
 */
var ImageCompresser = {
    /**
     * 检测ios平台是否有做过抽样处理
     * @param {Element} img
     */
    isIosSubSample: function(img){
        var w = img.naturalWidth,
            h = img.naturalHeight,
            hasSubSample = false;
        if (w * h > 1024 * 1024) { //超过1K*1K分辨率的图会被抽样
            var canvas = document.createElement('canvas');
                ctx = canvas.getContext('2d'),
            canvas.width = canvas.height = 1;
            ctx.drawImage(img, 1 - w, 0);
            hasSubSample = ctx.getImageData(0, 0, 1, 1).data[3] === 0;
            canvas = ctx = null;//清理
        }
        return hasSubSample;
    },

    /**
     * 获取ios上图片被压缩比例
        * 随机使用1px宽度尝试绘制样图，估算原图被ios压缩了多少
     * @param {Element} img
     * @param {Number} w
     * @param {Number} h
     */
    getIosImageRatio: function(img, w, h){
        var canvas = document.createElement('canvas'),
            ctx = canvas.getContext('2d'),
            data,
            sy = 0, //起始y坐标
            ey = h, //结束y坐标
            py = h; //当前判断的y坐标
        canvas.width = 1;
        canvas.height = h
        ctx.drawImage(img, 1 - Math.ceil(Math.random() * w), 0); //随机画1px宽度
        data = ctx.getImageData(0, 0, 1, h).data;
        while (py > sy) {
            var alpha = data[(py - 1) * 4 + 3];//Notice:如果原图自带透明度，这里可能会失效
            if (alpha === 0) {
                ey = py;
            }
            else {
                sy = py;
            }
            py = (ey + sy) >> 1;
        }
           return py / h;
    },

    /**
     * 获取图片base64
     * @param {Elemnt} img
     * @param {opts} opts
     *      opts.maxW {Number}  目标图片最大宽度
     *      opts.maxH {Number}  目标图片最大高度
     *      quality {Number}    目标图片压缩质量
     *      orien {Number}      目标图片旋转方向
     */
    getImageBase64: function(img, opts){ 
       
        //获取配置
        var maxW = opts.maxW, //图片最大限制
            maxH = opts.maxW,
            quality = opts.quality,
            _w = img.naturalWidth, //图片实际大小
            _h = img.naturalHeight,
            w, h; //图片目标大小
            
        var USER_AGENT = navigator.userAgent;
        var iphone = USER_AGENT.match(/(iPhone\sOS)\s([\d_]+)/);
        var android = USER_AGENT.match(/(Android)\s+([\d.]+)/);
        
        //ios平台针对大图做抽值处理
        if(iphone && ImageCompresser.isIosSubSample(img)){
            _w = _w / 2;
            _h = _h / 2;
        }
        //获取最终生成图片大小
        if(_w > maxW && _w/_h >= maxW/maxH){
            w = maxW;
            h = _h * maxW / _w;
        }
        else if(_h > maxH && _h/_w  >= maxH/maxW){
            w = _w * maxH / _h;
            h = maxH;
        }
        else {
            w = _w;
            h = _h;
        }
        //canvas临时工具
        var canvas = document.createElement('canvas'),
            ctx = canvas.getContext('2d'),
            base64Str;
           this.doAutoRotate(canvas, w, h, opts.orien);
        //ios平台贴瓷砖处理大图片
        if(iphone) {
            var tmpCanvas = document.createElement('canvas'),
                tmpCtx = tmpCanvas.getContext('2d'),
                d = 1024, //瓷砖canvas的大小
                vertSquashRatio = ImageCompresser.getIosImageRatio(img, _w, _h), //ios平台大尺寸图片压缩比
                sx, sy, sw, sh, dx, dy, dw, dh;
            tmpCanvas.width = tmpCanvas.height = d;
            sy = 0;
            while (sy < _h) {
                sh = sy + d > _h ? _h - sy : d,
                sx = 0;
                while (sx < _w) {
                    sw = sx + d > _w ? _w - sx : d;
                    tmpCtx.clearRect(0, 0, d, d);
                    tmpCtx.drawImage(img, -sx, -sy);
                    dx = Math.floor(sx * w / _w);
                    dw = Math.ceil(sw * w / _w);
                    dy = Math.floor(sy * h / _h / vertSquashRatio);
                    dh = Math.ceil(sh * h / _h / vertSquashRatio);
                    ctx.drawImage(tmpCanvas, 0, 0, sw, sh, dx, dy, dw, dh);
                    sx += d;
                }
                sy += d;
            }
            tmpCanvas = tmpCtx = null;
        }else {
            ctx.drawImage(img, 0, 0, _w, _h, 0, 0, w, h);
        }
        //android平台调用jpegEncoder处理生成jpg压缩格式
        if (android) {
            var imgData = ctx.getImageData(0, 0, canvas.width, canvas.height),
                encoder = new JPEGEncoder(quality * 100);
            base64Str = encoder.encode(imgData);
            encoder = null;
        }
        else {
            base64Str = canvas.toDataURL('image/jpeg', quality);
        }

       // console.log(base64Str);
        canvas = ctx = null;
        return base64Str;
    },
    /**
     * 旋转图片
     * @param {Element} canvas 画布
     * @param {Number} width 宽度
     * @param {Number} height 高度
     * @param {Number} orientation 旋转角度[1|2|3|4|5|6|7|8]
     */
    doAutoRotate: function(canvas, width, height, orientation) {
        var ctx = canvas.getContext('2d');
        if (orientation >= 5 && orientation <= 8) {
            canvas.width = height;
            canvas.height = width;
        }
        else {
            canvas.width = width;
            canvas.height = height;
        }
        switch (orientation) {
            case 2:
                // horizontal flip
                ctx.translate(width, 0);
                ctx.scale(-1, 1);
                break;
            case 3:
                // 180 rotate left
                ctx.translate(width, height);
                ctx.rotate(Math.PI);
                break;
            case 4:
                // vertical flip
                ctx.translate(0, height);
                ctx.scale(1, -1);
                break;
            case 5:
                // vertical flip + 90 rotate right
                ctx.rotate(0.5 * Math.PI);
                ctx.scale(1, -1);
                break;
            case 6:
                // 90 rotate right
                ctx.rotate(0.5 * Math.PI);
                ctx.translate(0, -height);
                break;
            case 7:
                // horizontal flip + 90 rotate right
                ctx.rotate(0.5 * Math.PI);
                ctx.translate(width, -height);
                ctx.scale(-1, 1);
                break;
            case 8:
                // 90 rotate left
                ctx.rotate(-0.5 * Math.PI);
                ctx.translate(-width, 0);
                break;
            default:
                break;
        }
    },
    /**
     * 获取文件地址
     * @param {File} file
     */
    getFileObjectURL: function(file){
        var URL = window.URL || window.webkitURL || false;
        if (URL) {
            return URL.createObjectURL(file);
        }
    },

    /**
     * 是否支持本地压缩
     */
    support: function(){
        return typeof(window.File) && typeof(window.FileList) && typeof(window.FileReader) && typeof(window.Blob);
    }
};


